package command

import (
	"pan/api"
	"pan/common/conf"
	"pan/common/log"
	"time"

	"github.com/jedib0t/go-pretty/v6/progress"
)

type FastDownloadCommand struct {
	user     string
	password string
	dir      string
	filename string
	savedDir string
	owner    string

	callback  *api.DownloadCallback
	pgWriter  progress.Writer
	pgTracker *progress.Tracker
}

func NewFastDownloadCommand() *FastDownloadCommand {
	return &FastDownloadCommand{}
}

func (f *FastDownloadCommand) Run(opts []*Option, args []string) {
	if !f.parseOption(opts) {
		return
	}

	if !conf.IsTokenValid() {
		if err := f.login(); err != nil {
			panic(err)
		}
	}
	req := &api.FastDownloadRequest{
		Owner:    f.owner,
		Dir:      f.dir,
		Filename: f.filename,
		SavedDir: f.savedDir,
	}
	f.callback = &api.DownloadCallback{
		Start:    f.downloadStart,
		Progress: f.downloadProgress,
		Finish:   f.downloadFinish,
	}

	err := api.FastDownloadApi(conf.GlobalToken.Tokenid, req, f.callback)
	if err != nil {
		panic(err)
	}
}

func (f *FastDownloadCommand) login() error {
	_, err := api.LoginApi(&api.LoginRequest{Account: f.user, Password: f.password})
	if err != nil {
		return err
	}
	return nil
}

func (f *FastDownloadCommand) downloadStart(dir, filename string, total int64) {
	p := progress.NewWriter()
	p.SetAutoStop(true)
	p.SetTrackerLength(2)
	p.ShowETA(true)
	p.ShowOverallTracker(true)
	p.ShowTime(true)
	p.ShowTracker(true)
	p.ShowValue(true)
	p.SetMessageWidth(50)
	p.SetNumTrackersExpected(1)
	p.SetStyle(progress.StyleDefault)
	p.SetTrackerPosition(progress.PositionRight)
	p.SetUpdateFrequency(time.Millisecond * 100)
	p.Style().Colors = progress.StyleColorsExample
	p.Style().Options.PercentFormat = "%4.1f%%"

	f.pgWriter = p

	go f.pgWriter.Render()

	f.pgTracker = &progress.Tracker{Message: filename, Total: total, Units: progress.UnitsDefault}

	f.pgWriter.AppendTracker(f.pgTracker)

	time.Sleep(time.Second * 1)
}

func (f *FastDownloadCommand) downloadProgress(num, written, total int64) {
	if f.pgTracker.IsDone() {
		return
	}

	if f.pgTracker.Value() >= total {
		f.pgTracker.MarkAsDone()
		return
	}
	f.pgTracker.Increment(num)
}

func (f *FastDownloadCommand) downloadFinish(written, total int64, err error) {
	time.Sleep(time.Millisecond * 200)
	if err == nil {
		log.Info("download success")
		return
	}
	if f.pgTracker != nil {
		f.pgTracker.MarkAsErrored()
	}
}

func (f *FastDownloadCommand) parseOption(opts []*Option) bool {
	for _, opt := range opts {
		switch opt.Name {
		case "user":
			f.user = opt.StrValue
		case "password":
			f.password = opt.StrValue
		case "dir":
			f.dir = opt.StrValue
		case "filename":
			f.filename = opt.StrValue
		case "save":
			f.savedDir = opt.StrValue
		case "owner":
			f.owner = opt.StrValue
		}
	}
	if !conf.IsTokenValid() {
		if f.user == "" {
			log.Error("user is invalid")
			return false
		}
		if f.password == "" {
			log.Error("password is invalid")
			return false
		}
	}

	if f.dir == "" {
		log.Error("doc dir path is invalid")
		return false
	}
	if f.filename == "" {
		log.Error("doc file name is invalid")
		return false
	}
	if f.savedDir == "" {
		log.Error("save dir is invalid")
		return false
	}
	return true
}

func (f *FastDownloadCommand) Arguments() []Argument {
	return nil
}

func (f *FastDownloadCommand) Options() []*Option {
	return []*Option{
		{
			ShortName:    "u",
			Name:         "user",
			Description:  "login username",
			OptType:      StrOption,
			DefaultValue: "",
		},
		{
			ShortName:    "p",
			Name:         "password",
			Description:  "login password",
			OptType:      StrOption,
			DefaultValue: "",
		},
		{
			ShortName:    "d",
			Name:         "dir",
			Description:  "doc dir path",
			OptType:      StrOption,
			DefaultValue: "",
		},
		{
			ShortName:    "f",
			Name:         "filename",
			Description:  "doc file name to download",
			OptType:      StrOption,
			DefaultValue: "",
		},
		{
			ShortName:    "s",
			Name:         "save",
			Description:  "save doc local dir",
			OptType:      StrOption,
			DefaultValue: "",
		},
		{
			ShortName:    "o",
			Name:         "owner",
			Description:  "doc owner name, default is current token's user",
			OptType:      StrOption,
			DefaultValue: "",
		},
	}
}

func (f *FastDownloadCommand) Description() string {
	return "One step to download"
}
